Corona – Triple Town style Matching Game Logic Part 2

The goal of this post is to create some Triple town style matching logic. Triple town if you haven’t played it is a very addictive matching game. The core concept is that you place elements on the game board. Three adjacent elements combine into a new elements. Elements combine in a progression.

In the last example I posted, I had created a grid with squares that cycled through colors: red, green, blue, yellow, magenta, cyan. This will by our progression. Tapping a square will color that square red. Three red squares will combine to form a green square, three green squares will combine to form a blue square etc.

I’ll be starting with the source code from the last post.

The first step is to retool the touch_tile() function. In the last example each touch advanced a tile through all of the colors in turn. Tapping an empty tile will color it red. Tapping other tiles will not effect.

local function touch_tile( event )
	local phase = event.phase
	
	if phase == "ended" then 
		local tile = event.target
		if tile.is_empty then 
			tile.is_empty = false
			tile.color_index = 1
			
			local r = color_array[ tile.color_index ].r
			local g = color_array[ tile.color_index ].g
			local b = color_array[ tile.color_index ].b
		
			tile:setFillColor( r, g, b )
		end 
		
		-- Matching logic logic starts here. 
		check_tile_match( tile )
	end 
end

When looking for matching tiles we might find any number of tiles that match. Define an array to hold the matched tiles. As we search for matching, and adjacent tiles, add them to this new array. When the search is complete examine the array to see how many matches there are.

The color_index property assigned to each represents the color displayed by the tile. This is what we will match. If two tiles have the same color_index they should display the same color. Create a variable to hold the match index while we search for a match.

local matched_array = {} -- An array to hold matched tiles
local match_color_index = 0 -- Match this color index

Searching adjacent tiles

To search for adjacent tiles we need to look at tiles that to the left, top, right and bottom of the current tile. Tiles are stored in tile_arrays. This is organized into arrays for containing tiles for each row. For example you could access the third tile in the second row with tile_array[2][3]. Think about about it this way: tile_array[row][column].

Imagine starting at tile_array[2][3]. To look at the four tiles surrounding this tile you’d need to get tiles:

  • tile_array[2][2] — left
  • tile_array[1][3] — top
  • tile_array[2][4] — right
  • tile_array[3][3] — bottom

You could think of this as:

  • tile_array[2][3-1] — left
  • tile_array[2-1][3] — top
  • tile_array[2][3+1] — right
  • tile_array[2+1][3] — bottom

Think about the surrounding adjacent tiles as coordinates specified in rows and columns:

  • 0, -1 — left
  • -1, 0 — top
  • 0, +1 — right
  • +1, 0 — bottom

After checking each of the adjacent tiles, if there is a match we can begin the search again from that tile. With each match we add that tile to the matched_array.

When checking tiles at the edge of the board some results will fall outside of the array. We’ll need to check for this.

Here’s a rough sketch of the code that will run the matching system:

local function check_neighbors( tile )
    -- look at adjacent tiles
    -- add a match to matched_array
    -- for each matched tile call check_neighbors( matching_tile )
end

This is called recession. Essentially the function above calls on itself. In Lua you’ll need to use a forward declaration or the function will not be able to “see itself”, and think it has not been declared.

local check_neighbors -- forward declaration
function check_neighbors( tile )
    -- ... code ...
    check_neighbors( matching_tile )
end

We also need some code to start the matching process and look at the results of the match check. Here’s the rough code

local check_neighbors -- Forward decalraitons
local check_tile_match

local function get_tile_frame_at_col_row( col, row )
    -- that tile at col, row is inside of the array

end 

function check_neighbors( tile )
    -- Check adjacent tiles for a match
    check_neighbors( matched_tile )
end 

function check_tile_match( tile )
    -- Find all matching adjacent tiles
    check_neighbors( tile ) -- Call recursive function to find all tiles
    -- look at the match results and set the colors of tiles accordingly
end 

local function touch_tile( event )
    check_tile_match( tile ) -- Call check_tile_match() with event.target
end

Here’s a full listing of the code:

-----------------------------------------------------------------------------------------
--
-- main.lua
--
-----------------------------------------------------------------------------------------

-- Your code here

local TILE_ROWS = 6
local TILE_COLS = 6
local TILE_SIZE = 50
local TILE_MARGIN = 1

local match_color_index = 0

local tile_array = {}
local color_array = {} 
local matched_array = {} -- An array to hold matched tiles

local game_group = display.newGroup()


local function Color( red, green, blue )
	return {r=red, g=green, b=blue}
end 

table.insert( color_array, Color(255, 0, 0) )
table.insert( color_array, Color(0, 255, 0) )
table.insert( color_array, Color(0, 0, 255) )

table.insert( color_array, Color(255, 255, 0) )
table.insert( color_array, Color(255, 0, 255) )
table.insert( color_array, Color(0, 255, 255) )

local check_neighbors
local check_tile_match

local function get_tile_frame_at_col_row( col, row )
	if col >= 1 and col <= TILE_COLS and row >= 1 and row <= TILE_ROWS then 
		return tile_array[row][col]
	else 
		return false
	end  
end 

function check_neighbors( tile )
	-- Get the row and col of this tile
	local row = tile.row
	local col = tile.col
	
	-- Define the coords of Left, Top, Right, and Bottom 
	local ltrb_array = { {row=0,  col=-1}, 
						{ row=-1, col=0 }, 
						{ row=0,  col=1 }, 
						{ row=1,  col=0 } }
						
	-- print("Check from tile:".. tile.row .. tile.col .. " " .. tile.alien.currentFrame  )
	
	-- Loop through left, top, right and bottom
	for i = 1, #ltrb_array, 1 do 
		local check_row = row + ltrb_array[i].row
		local check_col = col + ltrb_array[i].col
		-- Check that the row and col are on the board 
		local n_tile = get_tile_frame_at_col_row( check_col, check_row )
		
		if n_tile then -- on board
			if n_tile.color_index == match_color_index then -- matches
				-- Check that this tile doesn't exist in matched_array
				local index = table.indexOf( matched_array, n_tile )
				
				if index == nil then -- tile hasn't been found yet!
					print( "match at:" .. n_tile.row .. n_tile.col )
					table.insert( matched_array, n_tile ) -- add to array
					check_neighbors( n_tile )	-- recur this function with new tile
				end 
			end
		end
	end 
end 

function check_tile_match( tile )
	matched_array = {tile}					-- Add the first tile to the array
	match_color_index = tile.color_index	-- Get the index to match
	
	check_neighbors( tile ) -- Start looking for matching tiles
	
	-- Time to clear the tiles, if there are more than 2 matches
	if #matched_array > 2 then 				-- If more than two tiles match
		for i = 2, #matched_array, 1 do 	-- Loop through all but the first tile
			local tile = matched_array[i]	-- Clear all these tiles
			tile.color_index = 0
			tile.is_empty = true
			tile:setFillColor( 255, 255, 255, 100 )
		end 
		
		local tile = matched_array[1]				-- Get the first tile and 
		local color_index = match_color_index + 1	-- advance it's color
		local color = color_array[ color_index ]
		tile.color_index = color_index
		tile:setFillColor( color.r, color.g, color.b )
		tile.is_empty = false
		
		check_tile_match( tile )
	end 
end 
----------------------------------------------------------------------------------------





local function touch_tile( event )
	local phase = event.phase
	
	if phase == "ended" then 
		local tile = event.target
		if tile.is_empty then 
			tile.is_empty = false
			tile.color_index = 1
			
			local r = color_array[ tile.color_index ].r
			local g = color_array[ tile.color_index ].g
			local b = color_array[ tile.color_index ].b
		
			tile:setFillColor( r, g, b )
		end 
		-- Matching logic logic starts here. 
		check_tile_match( tile )
	end 
end


local function Tile()
	local tile = display.newRect( 0, 0, TILE_SIZE, TILE_SIZE )
	tile:setFillColor( 255, 255, 255, 100 )
	return tile
end 


local function make_grid()
	local tile_spacing = TILE_SIZE + TILE_MARGIN
	local offset_x = ( display.contentWidth - ( tile_spacing * TILE_COLS ) ) / 2
	offset_x = TILE_SIZE / 2 - offset_x
	
	for row = 1, TILE_ROWS, 1 do 
		local row_array = {}
		for col = 1, TILE_COLS, 1 do 
			local tile = Tile()
			game_group:insert( tile )
			tile.x = ( col * tile_spacing ) - offset_x
			tile.y = row * tile_spacing
			tile.row = row
			tile.col = col 
			
			tile.is_empty = true -- set this tile to empty
			tile.color_index = 0
			
			tile:addEventListener( "touch", touch_tile )
			table.insert( row_array, tile )
		end 
		table.insert( tile_array, row_array )
	end 
end 

make_grid()

Corona – Triple Town style Matching Game Part 1

Someone recently pointed out the game Triple Town for IOS. This is a really great little time waster. Game play is fun and challenging. It’s more of a board game rather than a real time game. You can play online also, they have a Flash version: http://www.tripletown.com/

The game is played on a grid, and the basic mechanic is to match three adjacent items. Matching three items of one type replaces the last item placed with a new item and removes the others. Matching three items leave you with a new advanced item. For example starting with two Grass, adding a third Grass combines all grass into a Bush. Three Bushes combine into a Tree, three trees combine into a House etc. here’s a chart:

 

This mechanic of combining three items and trading them up is very interesting. The game has a few other elements that add more options to game play.

I haven’t yet been able to get up to the sky tower or sky castle. I can make it up past 100K in points, then the Ninja Bears, yes Ninja Bears, cause so much trouble and I get stuck. You’ll have to play the original game if you want to meet the Ninja Bears.

The idea of finding trios of matching elements on a grid made for an interesting problem to solve. It took a few tries to get right. The solution I came up with was to look at the grid square where you placed a new “piece” and examine all of the adjacent squares for a match. From here you’ll need to recursively examine all of the matching squares for another match.

Recursion is the idea of having the same block of code execute itself. In my case I had a function that looked at a grid square, then examined the adjacent grid squares for matches. In this adjacent means top, left, right, and bottom, not diagonal. In other words starting a at grid square, look for matches in the adjacent squares, then use the same function to find other matching squares in the adjacent matches.

Try it for yourself

I started a new Corona project. I used the basic project so i started with only the main.lua, config.lua, build.settings file. To keep things simple I will stick with the built in shape objects and avoid images for now. By avoiding images and sprites I can concentrate on functionality without getting hung up with non related issues.

Creating a grid

The first step is to create a grid. The grid will be made up of squares, equal height and width. Each grid square will be a rectangle shape. The first step is to define some variables describing the grid.

local TILE_ROWS = 6
local TILE_COLS = 6
local TILE_SIZE = 50
local TILE_MARGIN = 1

These variables define the number of rows and columns in the grid. Rows run horizontal while columns run vertical. The grid will be 6 by 6. Since the tiles will be square, I used single variable to set the size. The margin is the space between tiles.

Making these variables uppercase is a convention to denote that they are constants. Constants are values that do not change, they are essentially fixed while the program runs. Lua doesn’t support true constants, the uppercase is a just a reminder.

With these variables in place at the top of our script we can change the values here to modify the grid arrangement. This is much easier, and more flexible than having the dig around in code to change things.

We will want to store all a reference to each of the tiles. For this I will use an array. For this I will define an array named: tile_array. I use the extension _array as a convention. This is not required but makes a good reminder this variable contains an array. The name also implies the array contains tiles.

All of the game elements should probably be contained in a group. This will allow use to move, scale, and rotate all of the game elements together. Here again I used an extension to remind myself that this element contains a group.

local tile_array = {}

local game_group = display.newGroup()

Tile factory

To keep my code in organized blocks I like to use factory functions to create elements. In this case I need tiles so I’m going to make a function that creates tiles, and initialize them, then returns a reference to the new tile.

local function Tile()
	local tile = display.newRect( 0, 0, TILE_SIZE, TILE_SIZE )
	tile:setFillColor( 255, 255, 255, 100 )
	return tile
end

This simple function creates a new rectangle of TILE_SIZE width and height. Sets the color to a transparent white. Then returns the tile. Any other standard tile features would be added here.

Make a grid of tiles

Now that I have all of the preliminary work in place I can make the grid. The function below contains two loops. The outer loop, loops once for each row. The inner loop, loops once for each column. Imagine starting in the upper left and creating TILE_COLS number of tile squares from left to right, then moving down one row and making all of the tiles left to right, continuing this process for TILE_ROWS.

local function make_grid()
	local tile_spacing = TILE_SIZE + TILE_MARGIN
	local offset_x = ( display.contentWidth - ( tile_spacing * TILE_COLS ) ) / 2
	offset_x = TILE_SIZE / 2 - offset_x

	print( display.contentWidth, tile_spacing * TILE_COLS, offset_x ) 

	for row = 1, TILE_ROWS, 1 do
		for col = 1, TILE_COLS, 1 do
			local tile = Tile()
			game_group:insert( tile )
			tile.x = ( col * tile_spacing ) - offset_x
			tile.y = row * tile_spacing
		end
	end
end

Positioning the tiles

The function above include some funny math at the top and a bit math in the middle to position the tiles. At the top I declared two local variables. Tiles spacing sets the space between each tile. This is the size of the tile plus the margin between tiles. Look inside the loop and you’ll see the x and y position of the tile is set to tile_spacing times row and col.

Tiles are positioned off their center point, and the first number we are count from is 1. I used offset_x to center the tiles inside the group. First I found the left over space by subtracting the total width of tiles from the width of the screen, then dividing by two. imagine the left over space is split on each side. Last I need to offset half the width of a tile, side the tiles are positioned on their center.

Also note that all tiles are added to the game_group.

Adding tiles to the array

The tiles need to be added to the tile_array. The array can act as a two dimensional storage space. Which may more accurately describe our tile grid. To do this we’ll use an array to store each row and store these row arrays in the tile_array.

local function make_grid()
	local tile_spacing = TILE_SIZE + TILE_MARGIN
	local offset_x = ( display.contentWidth - ( tile_spacing * TILE_COLS ) ) / 2
	offset_x = TILE_SIZE / 2 - offset_x

	for row = 1, TILE_ROWS, 1 do
		local row_array = {}
		for col = 1, TILE_COLS, 1 do
			local tile = Tile()
			game_group:insert( tile )
			tile.x = ( col * tile_spacing ) - offset_x
			tile.y = row * tile_spacing

			tile.row = row
			tile.col = col 

			table.insert( row_array, tile )
		end
		table.insert( tile_array, row_array )
	end
end

In this arrangement we will be able to access any tile with a row and col value. For example, the following would access the tile in the third row second column:

tile_array[2][3]

Also notice that I assigned each tile a row and col property. This way each tile will know it’s position in the grid. This will be important later one. Tapping a tile we can ask that tile it’s row and column.

Tapping the Grid

For this I’ll add a touch event to each tile. All of the touches can be handled from the same function since all tiles will know their row and col.

I’m using touch rather than tap as it provides more options.

For testing the touch function will print out the tiles row and column.

local function touch_tile( event )
	local phase = event.phase

	if phase == "ended" then
		local tile = event.target
		print( tile.row, tile.col )
	end
end

Using “ended” here creates an interaction that occurs after your finger lefts off the screen. I feel this might out, since if you were to touch down on the wrong tile you could drag your finger to the correct tile before the event was registered.

Register the event listener in make_grid().

local function make_grid()
	local tile_spacing = TILE_SIZE + TILE_MARGIN
	local offset_x = ( display.contentWidth - ( tile_spacing * TILE_COLS ) ) / 2
	offset_x = TILE_SIZE / 2 - offset_x

	for row = 1, TILE_ROWS, 1 do
		local row_array = {}
		for col = 1, TILE_COLS, 1 do
			local tile = Tile()
			game_group:insert( tile )
			tile.x = ( col * tile_spacing ) - offset_x
			tile.y = row * tile_spacing

			tile.row = row
			tile.col = col 

			tile:addEventListener( "touch", touch_tile )

			table.insert( row_array, tile )
		end
		table.insert( tile_array, row_array )
	end
end

Cycling colors

To keep things simple I’ll stick with shapes. Clicking a tile we need to change it in some way. For now I’ll just set the color. Colors are made up of red, green and blue values. It’s a good idea to keep them in a table. To this end a factory function would work well.

-- Make a function to return a color
local function Color( red, green, blue )
	return {r=red, g=green, b=blue}
end

In OOP languages constructors begin with an uppercase letter. I’ll follow this convention here. This is a simple function that takes three values, and returns a table containing three values r, g, and b.

Now let’s make some colors. The game will need to cycle through a series of colors in order. An array is needed to keep these organized.

local color_array = {} -- An array to store colors

Then make some colors and add them to the array.

table.insert( color_array, Color(255, 0, 0) )
table.insert( color_array, Color(0, 255, 0) )
table.insert( color_array, Color(0, 0, 255) )

table.insert( color_array, Color(255, 255, 0) )
table.insert( color_array, Color(255, 0, 255) )
table.insert( color_array, Color(0, 255, 255) )

 

Now tap to cycle through colors. When the game begins tiles will be empty. Tiles will take on a color when they are tapped. This means that a tile will need to keep track of it’s color. A couple variables are needed. Add a pair of property variables to each tile in make_grid().

tile.is_empty = true -- set this tile to empty
tile.color_index = 0

Now modify touch_tile() to handle the color change.

local function touch_tile( event )
	local phase = event.phase
	
	if phase == "ended" then 
		local tile = event.target
		if tile.is_empty then 
			tile.is_empty = false
			tile.color_index = 1
		else 
			tile.color_index = tile.color_index + 1
		end 
		
		local r = color_array[ tile.color_index ].r
		local g = color_array[ tile.color_index ].g
		local b = color_array[ tile.color_index ].b
		
		tile:setFillColor( r, g, b )
	end 
end

This post has set a basic tile board with some interactivity. The next post will apply some Triple Town style matching logic.

Below is a complete copy of the source code from this example.

Continue reading Corona – Triple Town style Matching Game Part 1

Corona – Tower Defense Game Experiments 14

Here’s a few thoughts on setting up waves of enemies. Plants vs Zombies makes waves of zombies and puts the waves to good use. Game play gets much more exciting after the message “A huge wave of Zombies is approaching.”

The game requires that you either a starting reserve of energy or you have to start with a fewer enemies. After building your defense for a while it becomes very easy to take on the enemies. This means that a larger wave of enemies is required to make the game more interesting at this point.

There are a lot approaches you could take to creating wave of enemies. I’m going to define a wave of enemies by describing the wave in terms of time between enemies, number of enemies in wave, and pool of enemies.

Time between enemies will be the amount of time between the creation of each new enemy.

Number of enemies in wave, will be the count of total enemies in this wave.

Pool of enemies will be a listing of the types of enemies in the wave. This is the most abstract idea here. I’m going to use the pool as a list of possible enemy types that might appear in the wave. During the wave each new enemy created will be a random type chosen from the pool. The pool will be an array. By adding the same type more than once the pool can weighted.

Each wave will be initiated by a timer.

Use three variables to keep track of the wave. One and array the other an integer setting the index of the current wave in the array. The last variable will keep track of a timer that tracks the wave.

local wave_timer -- add a timer to hold the wave
local alien_wave_index = 1 -- Use this to keep track of the current wave
-- Add an array to hold a wave of enemies	 
local alien_wave_array = { 
							{ time=2300, 		-- Time between enemies
							count=10, 			-- Number of enemies in wave
							pool={1,1,1,2,3}, 	-- Number and type of enemies in wave
							delay=3000
							} ,
							
							{ time=1500, 		-- Time between enemies
							count=20, 			-- Number of enemies in wave
							pool={1,2,3}, 		-- Number and type of enemies in wave
							delay=2000
							} 
						}

The array above holds a list of tables. Each of these tables describes a wave of enemies. Notice each table has properties of time, count, pool, and delay.

  • time – sets the time in ms between enemies during wave
  • count – total number of enemies in wave
  • pool – an array of alien types represented in wave
  • delay – time to wait after wave before starting the net wave

I added the extra delay property here as thought it might be useful to control the flow of things.

Next I needed two functions to control the waves of enemies. The make_wave() function sets up timers to run the wave. Here I create two timers. One called make_alien(). This timer takes the time and count from the current wave table. The second timer is set to total length of the current wave and is used to start the next wave.

I need to include a forward declaration here for next_wav, since this function calls make_wave and make wave calls it.

-- Need a forward declaration
local next_wave

-- Add this function to mange creating enemies that attack in waves. 
local function make_wave()
	local wave_table = alien_wave_array[ alien_wave_index ]
	local wave_time = wave_table.time
	local wave_count = wave_table.count 
	local delay_after_wave = wave_table.delay
	
	alien_timer = timer.performWithDelay( wave_time, make_alien, wave_count )
	local time_til_next_wave = ( wave_time * wave_count ) + delay_after_wave
	wave_timer = timer.performWithDelay( time_til_next_wave, next_wave, 1 )
end 

-- Called at the end of each wave
function next_wave()
	alien_wave_index = alien_wave_index + 1
	if alien_wave_index > #alien_wave_array then 
		print( "ALL WAVES COMPLETE" )
	else 
		print( "next wave" ) 
		make_wave()
	end 
end

make_wave()

Here’s a full listing of the code in this example:
Continue reading Corona – Tower Defense Game Experiments 14

Corona – Tower Defense Game Experiments 13

This series of posts has been going on for some time. I’m up to 13! I’m not done with the game yet, but it does have some interesting features.

In this post I’d like to add some “explosions”. What I really want is a small animated effect to show that an enemy has been hit by a bullet. For simplicity I’ll stick with the shapes and use a circle for the explosion. This could be replaced in the future.

The strategy here will be the same as was used with everything else, use factory function to create objects, and another function to remove the object when the explosion is finished.

Explosions will be animated with a transition animating the width and height. The onComplete will be used to remove the explosion when the animation finished.

-- Use this function to remove explosions
local function remove_explosion( explosion )
	display.remove( explosion )
end

-- Use this function to make explosions
local function make_explosion( x, y )
	local explosion = display.newCircle( 0, 0, 1 )
	explosion.x = x 
	explosion.y = y
	explosion:setFillColor( 0, 0, 255, 66 )
	explosion.strokeWidth = 3
	explosion:setStrokeColor( 0, 0, 255, 128 )
	alien_group:insert( explosion )
	transition.to( explosion, {width=20, height=20, time=500, onComplete=remove_explosion} )
end 

Above are the two functions. These are pretty simple. I made the explosions blue to separate them from the enemies (green), and the defenses (red).

The explosion is added to the alien_group. This keeps them inside the game_group, since alien_group is a child of game_group, and should keep new explosions on top of existing enemies.

All that’s need now is to call make_explosion( x, y ) and pass the x and y location where the explosion should occur. Bullets hit enemies in the check_bullets() function.

local function check_bullets()
	for b = 1, #bullet_array, 1 do 
		local bullet = bullet_array[b]
		if b > #bullet_array then 
			return
		end
		for a = 1, #alien_array, 1 do
			local alien = alien_array[a]
			if hit_test( bullet.x, bullet.y, alien.contentBounds ) then
				if alien.life > 0 then 
					make_explosion( alien.x, alien.y ) -- Add an explosion on a hit
					alien.life = alien.life - bullet.damage 
					local defense_name = bullet.defense_name
					
					if defense_name == "Stun" then	
						transition.cancel( alien.transition ) 				
						local t = ( alien_target_y - alien.y ) * ALIEN_SPEED 
						
						alien.transition = transition.to( alien, { y=alien_target_y, 
																	time=t, 
																	delay=300,	
																	onComplete=remove_alien } )
					end 
					
				else
					remove_alien( alien )
				end 
				remove_bullet( bullet )
				break
			end 
		end 
	end 
end

Find the comment in the function above. Here you can see a call to make_explosion( alien.x, alien.y ). This creates a new explosion at the location of the enemy. You might have also placed the explosion at the location of the bullet instead.

Here’s full listing:
Continue reading Corona – Tower Defense Game Experiments 13

Corona – Tower Defense Game Experiments 12

One aspect that will make the game more interesting is the addition of different types of enemies.

Let’s refer to Plants vs Zombies as our model. Here all of the enemies are zombies but there are different types with different capabilities. Besides the standard there are zombies that move faster, zombies that withstand more damage, zombies that jump over a defense, and more.

The variety of enemies adds a lot to strategies that players can employ, and creativity that developers can employ when creating levels.

Enemy features

Enemies can have as may features as you can imagine. Here’s a few ideas that fit into the game as I have been envisioning it so far.

  • speed – Some enemies move faster than others
  • Toughness – some enemies take more damage to destroy than others
  • Special – some enemies may have special features or attacks

To keep track of the enemy types I created an array similar to the array used for organizing defense types. Each enemy type will be described in a table with properties:

  • name – name of feature
  • speed – sets speed in px per second
  • life – sets the starting life value for this enemy type
  • green – color of enemy type

The last property, green, is just used for this example. Later we will have graphics to replace the shapes.

All of the enemy type tables will be held in an array for easy access and organization.

-- Add an array to manage enemy types 	
local alien_type_array = {
			{ name="normal", speed=ALIEN_SPEED, 	life=5, green=200 }, 	-- Normal enemy
			{ name="fast", 	 speed=ALIEN_SPEED / 2, life=2, green=255 },	-- Fast enemy weaker
			{ name="slow",   speed=ALIEN_SPEED * 2, life=10, green=165 }}	-- slow enemy tougher

make_alien()

You might make different enemy types based on different criteria or different situations. In this example to keep things simple I will make the choice of enemy type random. Each time an enemy is created I will choose a random type and configure the new enemy based on the information in the tables created above.

-- Modify this function to select different types of aliens
local function make_alien()
	local alien_type = alien_type_array[ math.random( 1, #alien_type_array ) ] -- Choose a random alien type
	
	local alien = display.newRect( 0, 0, 32, 32 )
	alien.alien_type = alien_type					-- Save the type
	alien:setFillColor( 0, alien_type.green, 0 )	-- get the green value
	local col = math.random( 1, TILE_COLS )
	alien.col = col
	alien.x = col * ( TILE_SIZE  + TILE_MARGIN ) 
	alien.y = 0
	alien.life = alien_type.life -- Get the life foe this type
	alien.speed = alien_type.speed -- Save the speed 
	
	local t = alien_target_y * alien_type.speed -- Get the speed for this type
	alien.transition = transition.to( alien, {y=alien_target_y, time=t, onComplete=remove_alien} )
	alien_group:insert( alien ) 
	table.insert( alien_array, alien )
end 

Here we’re creating the enemies as before. The difference this time is that property values are set to starting values based on values found in the tables in the alien_type_array.

Last, since the speed can be set after an alien gets hit with a stun weapon, we should make sure the alien moves at it’s types speed after it is hit with a stun weapon. Look at check_bullets() function.

local function check_bullets()
	for b = 1, #bullet_array, 1 do 
		local bullet = bullet_array[b]
		if b > #bullet_array then 
			return
		end
		for a = 1, #alien_array, 1 do
			local alien = alien_array[a]
			if hit_test( bullet.x, bullet.y, alien.contentBounds ) then
				if alien.life > 0 then 
					alien.life = alien.life - bullet.damage 
					local defense_name = bullet.defense_name
					
					if defense_name == "Stun" then	
						transition.cancel( alien.transition ) 				
						local t = ( alien_target_y - alien.y ) * alien.speed -- Use this aliens speed here 
						
						alien.transition = transition.to( alien, { y=alien_target_y, 
																	time=t, 
																	delay=300,	
																	onComplete=remove_alien } )
					end 
					
				else
					remove_alien( alien )
				end 
				remove_bullet( bullet )
				break
			end 
		end 
	end 
end

Here’s the full listing

Continue reading Corona – Tower Defense Game Experiments 12

Corona – Tower Defense Game Experiments 11

So far we have the makings of a game but, there are more than a few that need to be taken care of. For example, the buttons do not show the energy cost. This makes it hard to play and test, since it’s hard to tell what the cost is for defenses.

Groups as layers again

The buttons that I had created earlier were simple shapes. To show both text and a shape we need to create a group and add both elements to the group. Groups in Corona have all of the common display properties available to other display objects.

To make this work out I created a group for each button and used this to replace the original shape I had used for the button. Then I added the original rounded rectangle to the group. Then created a new Text shape and added that to the new group also.

I need to keep a reference to the rounded rectangle shape and text field. So I added properties to the group to hold these.

From here I retooled the rest of the script so all of the properties that had been attached to the button shape were now attached to the button_group. I also inserted the button_group into the defense_button_array in place of the original button shape. I also added the button_group into the control_group.

To get the costs to chose up in the text field I needed to get the cost from the defense_type_array for the current defense type and set it as the text of button_text.

Last I needed to adjust the positions of all three objects: button_group, button, and button_text.

local function make_defense_buttons()
	for i = 1, #defense_type_array, 1 do
		local button_group = display.newGroup() -- Make a group to hold all button elements

		local button = display.newRoundedRect( 0, 0, 40, 40, 6 )
		local r = 255 * ( i / #defense_type_array )
		button:setFillColor( r, 0, 0 )
		button:setStrokeColor( 255, 255, 255 )
		defense_type_array[i].red = r 

		local button_text = display.newText( "0", 0, 0, native.systemFontBold, 14 ) -- make a text field
		button_text.text = defense_type_array[i].cost -- Display the cost
		button_text.x = 20	-- Set the position of the label
		button_text.y = 20	-- Set the position of the label

		button_group:insert( button ) 		-- Add button shape to group
		button_group:insert( button_text ) 	-- Add text to group

		button_group.shape = button -- add button shape as a property to group
		button_group.label = button_text -- add button text as property of group

		-- Assign these properties to button group
		button_group.index = i
		button_group.x = display.contentWidth - 45 -- adjust the position
		button_group.y = 40 + ( i * 50 )
		button_group:addEventListener( "touch", touch_defense_button )

		table.insert(defense_button_array, button_group ) -- Add button group to array
		control_group:insert( button_group ) -- add button group to control group
	end
end

The select_defense_button() function needs a little work also. This function needs to now set the stroke of the shape rather than the button. After the changes above the button will be a group rather than a shape.

local function select_defense_button()
	for i = 1, #defense_button_array, 1 do
		local button = defense_button_array[i]
		if button.index == current_defense_type then
			button.shape.strokeWidth = 3 -- set the stroke of the shape
		else
			button.shape.strokeWidth = 0 -- set the stroke of the shape
		end
	end
end

Showing disabled buttons

If a defense is not available to a player, due to not having enough energy to meet the cost, it should display as disabled. For this example I’ll make buttons that are disabled appear transparent. When a button is available it will be opaque.

Add a new function to handle this above touch_defense_button(). This new function will loop through each button in the defense_button_array and compare it’s cost to the current energy value and set it’s alpha accordingly.

-- *** Add a new function to enable and disable buttons based on energy available
local function enable_disable_buttons()
	for i = 1, #defense_button_array,1 do 
		local button = defense_button_array[i]
		local cost = button.cost
		if cost < energy then 
			button.enabled = true
			button.alpha = 1.0
		else 
			button.enabled = false
			button.alpha = 0.5
		end 
	end
end 

To set up the initial state for these buttons we should call on this function when the game begins. Place a call below make_defense_buttons().

enable_disable_buttons()

Last, when the energy value changes we need to update the buttons to show a new state. Find the energy_recharge() function and add a call to enable_disable_buttons() there.

local function energy_recharge()
	energy = energy + ENERGY_RECHARGE_RATE
	enable_disable_buttons() -- *** Update buttons 
	update_energy()
end>

This works here but might need to be rethought if the recharge rate were slower.

Here's a full listing of the code

Continue reading Corona – Tower Defense Game Experiments 11

Corona – Tower Defense Game Experiments 10

Giving the player the ability to place different types of defenses adds interest to the game. It opens up different types of strategies and different types of game play.

Looking at Plants vs Zombies you will see a wide variety of defense types. Here’s a list of the types of plants available: http://plantsvszombies.wikia.com/wiki/Gallery_of_Plants

Defenses can have a variety of features. Core ideas might be:

  • Damage – how much damage the defense applies to an enemy
  • Rate of fire – how often the defense fires
  • Special effect – A special ability only applied to this type of defense
  • Cost – The energy cost to place the defense

Really you could boil the list down cost vs power. This is the essential formula that creates balance and inspires game play. All of the features, except cost, are a measure of power for a defense. Cost is the balancing factor. Energy is collected over time, gives players the choice to build fewer more expensive defenses, or more less powerful defenses, or build a mix of each.

The key factor to making the game playable is a balance of cost vs power. Adding a mix of special features add a lot of interest to the game, provided the special features work well in cost vs power balance. As the programmer you can make anything happen. You can make the most powerful weapons cost very little. But this makes for an uninteresting playing experience. As a game design this is where you your real work. Finding the right balance of cost vs power for each element while providing some interesting effects.

In the example here I’ll keep the features simple. each defense will have a rate of fire, damage, and a cost.

Rate of fire will set the interval, in milliseconds, between shots for a defense.

Damage will determine how much subtracted from an enemies life property with each hit.

Cost sets the amount of energy that is paid to create this type of defense.

I’ve also added one special feature. One type of defense will also momentarily stop an approaching alien.

defense_type_array

This array will hold a description of each defense type. With properties holding values for each of the features above. Here’s an example:

{name="Standard",	rof=1000,	damage=1,	cost=50}

This is standard defense, it all of the features of the original defense. It fires once every 1000 ms, it subtracts 1 from the life of an enemy with each hit, and costs 50 energy to create.

The name property will be used for special abilities.

I created an array of these tables named defense_type_array:

local defense_type_array = {
			{name="Standard",	rof=1000,	damage=1,	cost=50},
			{name="Rapid",		rof=800,	damage=1,	cost=75},
			{name="Heavy",		rof=2000,	damage=3,	cost=100},
			{name="Stun",		rof=1200,	damage=0.5,	cost=80}
							}

There will be one button for each of items in this array.

We need to be able to identify each defense placed on the board. So far I haven’t used any graphics, so there isn’t a picture for each, yet. For now I will match the color of the button to the color of the defense. When the buttons are created I generate a color for each. As a temporary measure I will put the color in the defense type tables for easy reference.

In the make_defense_button() function add the following:

local function make_defense_buttons()
	for i = 1, #defense_type_array, 1 do
		local button = display.newRoundedRect( 0, 0, 40, 40, 6 )
		local r = 255 * ( i / #defense_type_array )

		-- For this example I'll put the red values in each of these tables
		-- this way we can color each of the defense elements to match the buttons.
		defense_type_array[i].red = r 

		button.index = i
		button:setFillColor( r, 0, 0 )
		button:setStrokeColor( 255, 255, 255 )
		button.x = display.contentWidth - 26
		button.y = 40 + ( i * 50 )
		button:addEventListener( "touch", touch_defense_button )
		table.insert(defense_button_array, button )
		control_group:insert( button )
	end
end

touch_tile()

Touching a tile creates a new defense. This is also where we check the available energy and pay the cost for the defense.

local function touch_tile( event ) -- Check the type of defense
	local phase = event.phase
	if phase == "began" then
		local tile = event.target
		local tile_x = tile.x
		local tile_y = tile.y

		local cost = defense_type_array[current_defense_type].cost -- Get the cost for this defense type

		if energy >= cost then -- Use cost here
			energy = energy - cost -- and here
			local defense = make_defense( tile_x, tile_y )
			defense.col = tile.col
		end
	end
end

make_defense()

Each defense will now have a type and each will have different abilities. Each defense should keep track of it’s features: roy, damage and defense_name.

As an alternative, each defense could hold a reference to the table describing the defense features. Here I chose the first option. If there were many defense features the second option might be better.

local function make_defense( x, y )
	local defense = display.newRect( 0, 0, 32, 32 )

	-- Get all of the properties describing this weapon and store them in the new defense
	defense.rof 		 = defense_type_array[current_defense_type].rof
	defense.damage 		 = defense_type_array[current_defense_type].damage
	defense.defense_name = defense_type_array[current_defense_type].name
	defense.red 		 = defense_type_array[current_defense_type].red

	defense:setFillColor( defense.red, 0, 0 )
	defense_group:insert( defense )
	defense.x = x
	defense.y = y
	table.insert( defense_array, defense )
	defense.timer = timer.performWithDelay( defense.rof, function() defense_defend( defense ) end, -1 )
	return defense
end

Here I just transferred the features across and set them as properties of the defense that was created. Notice that I also got the red property and used this to set the color of the defense. The defense should now match the color of button. Later when images are added we can dump the color.

make_bullet()

Bullets created earlier were all the same. Now we want them to have unique properties described by the defense that fired them. The make_bullet() function doesn’t have a reference to the defense. But, it is called from the defense_defend() function that does have a reference to the defense. To share information between the two I’ll have make_bullet() return a reference to the bullet.

local function make_bullet( x, y )
	local bullet = display.newCircle( 0, 0, 5 )
	bullet:setFillColor( 0, 0, 0 )
	bullet.x = x
	bullet.y = y
	table.insert( bullet_array, bullet )

	local bt = y * BULLET_SPEED
	bullet.transition = transition.to( bullet, {y=0, time=bt, onComplete=remove_bullet} )
	return bullet -- better return the bullet so the defense_defend() function can work with it
end

defense_defend()

The defense_defend() function creates bullets. Each bullet will need to know it’s damage value. To get the damage we need to have a reference to the defense. Here we get the bullet that was returned and assign it the damage and the name of the defense type that fired it. The name is important since I’ll use it for special effects.

Damage is easy, instead of subtracting 1 from alien.life. Here we replace this with bullet.damage. In this way each bullet can subtract it’s own damage value.

Next we need to check the defense_name. If the name is “Stun” I need to stop the enemy, and then start again after a short delay. Since the movement is handled by a transition we need to cancel the previous transition. Then add a new transition with a delay. Here I used the ALIEN_SPEED constant to make sure the enemy is moving at the same speed.

To get the speed right I needed to know the distance. To get the remaining distance to move the enemy I subtracted the current y from the alien_target_y value.

local function defense_defend( defense )
	for i = 1, #alien_array, 1 do
		local alien = alien_array[i]
		if alien.col == defense.col then
			local bullet = make_bullet( defense.x, defense.y ) -- Get the bullet
			bullet.damage = defense.damage 	-- assign a damage value to the bullet
			bullet.defense_name = defense.defense_name 		-- get the name of the defense
			break
		end
	end
end

make_alien()

I want to add a weapon with a special feature. One of the weapons will “Stun” an enemy. This will have the effect of stopping the enemy momentarily. To make this effect happen the current transition will have to be removed from the enemy and replaced with a new transition. The new transition will have a delay.

The challenge here is making the enemy continue moving at the same speed to the same end point as before it was stopped. To make this happen I need to know the end point, and know the rate of movement.

The end point for enemies was calculated in the make_alien() function previously. To make things more organized and efficient I defined a variable to hold the ending y value for enemies.

local alien_target_y = ( TILE_SIZE + TILE_MARGIN ) * TILE_ROWS -- Ending y value for aliens

This would need to be defined after TILE_SIZE, TILE_MARGIN and TILE_ROWS are defined. This value will probably not change, so it could have be declared as a constant I suppose.

Enemies will also need a rate of movement in px per sec. I defined this at the top as a constant.

local ALIEN_SPEED = 1000 / 20 	-- Assign an alien speed 20px per sec

Multiplying this by the distance will give us the time in ms that enemies will move at a rate of 20 px per sec.

Now we need to retool the make_alien function() to make use of these new variables.

local function make_alien()
	local alien = display.newRect( 0, 0, 32, 32 )
	alien:setFillColor( 0, 200, 0 )
	local col = math.random( 1, TILE_COLS )
	alien.col = col
	alien.x = col * ( TILE_SIZE  + TILE_MARGIN )
	alien.y = 0
	alien.life = 5
	-- Change the alien movement
	local t = alien_target_y * ALIEN_SPEED
	alien.transition = transition.to( alien, {y=alien_target_y, time=t, onComplete=remove_alien} )
	alien_group:insert( alien )
	table.insert( alien_array, alien )
end

Since enemies start at y of 0. The distance then move is alien_target_y. Multiply this by the ALIEN_SPEED and we get the time in ms for the transition. Notice that I removed some of the other code that was here from the previous example.

check_bullet()

This function checks for bullets hitting enemies. We need to add two new features here: apply damage for specific bullet/defense types, and any special features for any specific bullet type. In this example only the “Stun” type defense will have a special effect.

The

local function check_bullets()
	for b = 1, #bullet_array, 1 do
		local bullet = bullet_array[b]
		if b > #bullet_array then
			return
		end
		for a = 1, #alien_array, 1 do
			local alien = alien_array[a]
			if hit_test( bullet.x, bullet.y, alien.contentBounds ) then
				if alien.life > 0 then
					alien.life = alien.life - bullet.damage -- Use the damage value of the bullet
					local defense_name = bullet.defense_name -- Get the name of the defense
					-- Check the defense name and apply special stuff
					if defense_name == "Stun" then
						transition.cancel( alien.transition ) 				 -- Cancel the current transition
						local t = ( alien_target_y - alien.y ) * ALIEN_SPEED -- Calculate a new speed
						-- Add a new transition with a delay
						alien.transition = transition.to( alien, { y=alien_target_y,
																	time=t,
																	delay=300,	-- Delay
																	onComplete=remove_alien } )
					end 

				else
					remove_alien( alien )
				end
				remove_bullet( bullet )
				break
			end
		end
	end
end

Here’s a listing of the entire code used so far.

Continue reading Corona – Tower Defense Game Experiments 10

Corona – Tower Defense Game Experiments 9

With one type of defense the only choice a player has is where to place a defense. Providing a choice of defense types gives players a chance to try different strategies. Plants vs Zombies provides a wide range of defense types each with a range of effects and cost.

As a first step to getting different types of defenses to work I need to have an interface to choose the type of defense to place. I don’t want to get into a long discussion what the best type of interface might be. The goal for this post will be to make a simple set of buttons that will act like a radio button group. Tapping one button will select it and deselect the currently selected button. Only one button can be selected at a time.

This idea could be applied to many other projects!

The buttons

The buttons will be rounded rectangles filled with a color. I’ll use a white stroke to show which is selected.

List types of defenses

The types of defense will be stored in an array. Knowing how many different types of defenses are available will tell us how many buttons to make.

For now the types of defenses can be anything. Later I will look at the features of each defense type and we can store that information. For now this array can store anything as long as there one element for each type. in the example I used the letters: “A”, “B”, “C” etc.

Keeping track of the current defense type

I added a new variable: current_defense_type. This variable holds the index of the current defense type in the defense_type_array. For example if the current defense type is “B”, then current_defense_type would be 2.

local current_defense_type = 1 -- marks the current defense type, matches the index of the defense type in the defense_type_array

List of buttons

The buttons will also be stored in an array. This is essential for keeping track of the buttons. Having an array of the buttons will make it easy to select and deselect any of the buttons in the array.

local defense_type_array = {"A","B","C","D"} -- Make an array to keep track of defense buttons 
local defense_button_array = {} -- use an array to keep track of buttons

The functions

I used three functions make_defense_buttons(), touch_defense_button(), and select_defense_button().

make_defense_buttons()

This function makes the defense buttons. It makes one button for each item in the defense_type_array. Each button is given a different shade of red, and a white stroke. The buttons are also assigned the property index. This property is the index of the defense type in the defense_type_array that the button corresponds to. I also added a touch event to each button that is handled by touch_defense_button().

touch_defense_button()

This function gets the index from the button and sets current_defense_type to this value. Then it calls select_defense_button().

select_defense_button()

This function highlights the current button by setting the stroke width to 3 for that button and the stroke width of the other buttons to 0.

-- Select the current button
local function select_defense_button()
	for i = 1, #defense_button_array, 1 do 
		local button = defense_button_array[i]
		if button.index == current_defense_type then 
			button.strokeWidth = 3
		else
			button.strokeWidth = 0
		end 
	end
end

-- Handle button events 
local function touch_defense_button( event )
	local button = event.target
	current_defense_type = button.index
	select_defense_button()
end

-- Add a function to create defense buttons
local function make_defense_buttons()
	for i = 1, #defense_type_array, 1 do 
		local button = display.newRoundedRect( 0, 0, 40, 40, 6 )
		local r = 255 * ( i / #defense_type_array )
		button.index = i
		button:setFillColor( r, 0, 0 )
		button:setStrokeColor( 255, 255, 255 )
		button.x = display.contentWidth - 26
		button.y = 40 + ( i * 50 )
		button:addEventListener( "touch", touch_defense_button )
		table.insert(defense_button_array, button )
		control_group:insert( button )
	end 
end

-- Call the function to make the buttons
make_defense_buttons()
-- Select the current defense type
select_defense_button()

Here’s a full listing of the code so far:
Continue reading Corona – Tower Defense Game Experiments 9

Corona – Tower Defense Game Experiments 8

A key factor to the tower defense game is the economy. If there is no limiting factor to how fast defenses can be created there isn’t much challenge since a player can quickly fill the board with defenses.

There needs to be a limiting factor in how often a player can place a defense. Here I will set up a simple system with an energy value that increases over time and incur an energy cost for placing defenses.

The key to making this system form an interesting game is balancing all of the factors. All of the factors need to be considered. Here’s a list:

  • Speed of enemies – Faster enemies are harder to deal with
  • Speed of bullets – Faster bullets can take care of closer range enemies before a defense is destroyed
  • Defense rate of fire – Defenses that fire faster are more powerful
  • Energy cost to place a defense – Lower cost allows defense to be placed more often
  • Energy Recharge rate – The faster your energy recharges the more often you can place a defense

Note: Setting a cap on total available energy would be another idea to interest to game play. I didn’t do that here but it would not be hard to add.

This example will add a variable to track energy. Energy will recharge over time at a fixed rate. Placing a defense incurs an energy cost.

First I added a few constants at the top of the script to set fixed values.

Energy recharge rate sets the amount of energy is added each timer the energy timer updates. Energy defense cost sets the value subtracted from energy each time a defense is placed. Energy timer time sets the time in milliseconds that energy is recharged, added to energy.

local ENERGY_RECHARGE_RATE = 1 -- Set the rate to recharge
local DEFENSE_ENERGY_COST = 50 -- Set the cost for a defense
local ENERGY_TIMER_TIME = 150	-- Timer to recharge energy

We also need a few variables to keep track of energy and timers. Energy holds your current energy. Energy timer holds a reference to the timer that updates energy.

Note, I moved the alien timer to the top of my script to keep all of the timers together. This variable is not new.

local alien_timer 	-- Moved this to the top
local energy_timer 		-- reference the energy timer
local energy = 0 		-- set the starting energy

I needed a text field to display the current energy value. I defined this at the top since it might be accessed from any where.

local energy_text -- Declare a text field to display energy

I thought it might be good to have the energy display and other UI elements in their own group. So I added a group to hold these:

local control_group = display.newGroup() -- Add a group for UI stuff

Next I need to add a function to update the energy display, and a function to increase the energy value. I separated these into two functions thinking it might be more flexible in the future if I need to include code to position and adjust the position of the text field with each update.

The update_energy() function displays the current energy value in the text field.

The energy_recharge() function increase the energy value, then calls update_energy() to refresh the display.

In this arrangement the energy display is only updated when energy is increased. This works if the energy recharge rate is not too slow. If the recharge rate is slow you you could place a defense and not see the energy value update until the recharge timer updates energy. If this is effecting you, add a call to update_energy() to make_defense().

Last I added create the energy timer. Here we create a new timer that updates at the rate set by ENERGY_TIMER_TIME. With each update it calls energy_recharge(), and loops forever.

local function update_energy()
	energy_text.text = energy
end 

local function energy_recharge()
	energy = energy + ENERGY_RECHARGE_RATE
	update_energy()
end

energy_timer = timer.performWithDelay( ENERGY_TIMER_TIME, energy_recharge, -1 ) 

Last, I need to incur the energy cost for placing a defense element. Basically this means checking that there is sufficient energy to pay for a defense. If there is sufficient energy, subtract the cost from energy and create the defense.

New defense elements are created in the touch_tile() handler. Here I added a little logic to check the energy, subtract the energy cost and place the new defense.

local function touch_tile( event )
	local phase = event.phase
	if phase == "began" then
		local tile = event.target
		local tile_x = tile.x
		local tile_y = tile.y
		if energy >= DEFENSE_ENERGY_COST then 		-- Check the energy
			energy = energy - DEFENSE_ENERGY_COST	-- Pay energy for defense
			local defense = make_defense( tile_x, tile_y ) 
			defense.col = tile.col 
		end 						  
	end
end

Still the game is lacking many features that would make it truly interesting to play. That said, what we have here is an outline of the mechanics that cover many of the elements that make the game function. Building on these ideas, adding compelling art, and a theme is what will make the game interesting.

Here’s the full source code

Continue reading Corona – Tower Defense Game Experiments 8

Corona – Tower Defense Game Experiments 7

Time for the enemies to strike back. So far the defenses have it easy, there is no way to remove a defense. There are a lot of things we can do here. In this example I’ll just take a simple step and remove a defense if an enemy intersects it. This will let the game play and tutorial advance slowly. I find I get better results if I build things from smaller steps.

The first step here will be to check if an enemy is intersecting a defense. The earlier hit_test(x,y, bounds) function works well with bullets which are small size. With larger elements the center point of an object may be outside of another object, but the two objects might be overlapping still. To solve this we can use a different type of hit test comparing the bounds of both objects.

Here’s a simple function that tests for overlapping boundaries. This was posted here by jhocking: http://developer.anscamobile.com/code/flashs-hittestobject-emulated-using-contentbounds. I modified the function slightly but it is essentially the same.

local function hit_test_bounds( bounds1, bounds2 )
        return bounds1.xMin < bounds2.xMax
                and bounds1.xMax > bounds2.xMin
                and bounds1.yMin < bounds2.yMax
                and bounds1.yMax > bounds2.yMin
end 

This uses the boundaries of an object. imagine the boundary as a rectangle that just fits the object.

Now we need check for overlap between aliens and defense elements. For this we’ll need to loop through the alien_array and use the function above to check for an overlap with each of the defenses in defense_array. On a true from hit_test_bounds() remove that defense and break the loop.

local function check_enemies()
	for a = 1, #alien_array, 1 do 
		local alien = alien_array[a]
		
		for d = 1, #defense_array, 1 do 
			local defense = defense_array[d]
			-- Here we're use the new hit_test_bounds() function to check if the defense and alien overlap
			if hit_test_bounds( alien.contentBounds, defense.contentBounds ) then -- Check for collision
				remove_defense( defense )	-- Remove this defense on a collision
				break
			end 
		end 
	end 
end

Add a call to this function in the enterFrame. Have to check this each frame.

local function on_enterframe( event ) 
	check_bullets()
	check_enemies()
end

Remember, when creating a defense a timer is added which fires a bullet from the position of the defense. If the defense is removed it’s timer should also be removed. Update remove_defense():

local function remove_defense( defense )
	local index = table.indexOf( defense_array, defense ) 
	timer.cancel( defense.timer )	-- Must remove the timer! 
	table.remove( defense_array, index )				  
	display.remove( defense )
end 

Continue reading Corona – Tower Defense Game Experiments 7